Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / vendor / lxmfy / docs / source / api-reference.rst

Displaying Raw • Download


vendor/lxmfy/docs/source/api-reference.rst e5756d7ab065475a18acdcafc008a767fcff87e0 (e5756d7a) Text, 21.20 KB

Tc9d1d9Core Components
Tc9d1d9================

Tc9d1d9LXMFBot
Tc9d1d9--------

The main bot class that handles message routing, command processing, and bot lifecycle management.

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3LXMFBot

Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffMyBotTa5d6ff"Tb4b4b4,
Te6edf3announceTff7b72=T79c0ff600Tb4b4b4,
Te6edf3announce_immediatelyTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3adminsTff7b72=Tffa657setTb4b4b4(Tb4b4b4)Tb4b4b4,
Te6edf3hot_reloadingTff7b72=Tff7b72FalseTb4b4b4,
Te6edf3rate_limitTff7b72=T79c0ff5Tb4b4b4,
Te6edf3cooldownTff7b72=T79c0ff60Tb4b4b4,
Te6edf3max_warningsTff7b72=T79c0ff3Tb4b4b4,
Te6edf3warning_timeoutTff7b72=T79c0ff300Tb4b4b4,
Te6edf3command_prefixTff7b72=Ta5d6ff"Ta5d6ff/Ta5d6ff"Tb4b4b4,
Te6edf3cogs_dirTff7b72=Ta5d6ff"Ta5d6ffcogsTa5d6ff"Tb4b4b4,
Te6edf3cogs_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3permissions_enabledTff7b72=Tff7b72FalseTb4b4b4,
Te6edf3storage_typeTff7b72=Ta5d6ff"Ta5d6ffjsonTa5d6ff"Tb4b4b4, T8b949e# "json", "sqlite", or "memory"
Te6edf3storage_pathTff7b72=Ta5d6ff"Ta5d6ffdataTa5d6ff"Tb4b4b4,
Te6edf3first_message_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3event_logging_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3max_logged_eventsTff7b72=T79c0ff1000Tb4b4b4,
Te6edf3event_middleware_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3announce_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3signature_verification_enabledTff7b72=Tff7b72FalseTb4b4b4,
Te6edf3require_message_signaturesTff7b72=Tff7b72FalseTb4b4b4,
Te6edf3identity_pinning_enabledTff7b72=Tff7b72FalseTb4b4b4,
Te6edf3message_persistence_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3dynamic_cogs_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3external_cogs_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3external_cogs_sandbox_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3external_cogs_sandbox_typeTff7b72=Ta5d6ff"Ta5d6ffautoTa5d6ff"Tb4b4b4, T8b949e# "auto", "landlock", "bwrap", "firejail", "none"
Te6edf3external_cogs_timeoutTff7b72=T79c0ff30Tb4b4b4,
Te6edf3landlock_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3nlp_enabledTff7b72=Tff7b72FalseTb4b4b4,
Te6edf3nlp_thresholdTff7b72=T79c0ff0.5Tb4b4b4,
Te6edf3link_support_enabledTff7b72=Tff7b72FalseTb4b4b4,
Te6edf3lxmf_commands_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3message_queue_sizeTff7b72=T79c0ff50Tb4b4b4,
Te6edf3reticulum_config_dirTff7b72=Tff7b72NoneTb4b4b4, T8b949e# or LXMFY_RETICULUM_CONFIG_DIR / "~/.reticulum"
Te6edf3rrc_enabledTff7b72=Tff7b72FalseTb4b4b4,
Te6edf3rrc_hubsTff7b72=Tb4b4b4[Tb4b4b4]Tb4b4b4,
Te6edf3rrc_roomsTff7b72=Tb4b4b4[Tb4b4b4]Tb4b4b4,
Te6edf3rrc_nickTff7b72=Tff7b72NoneTb4b4b4,
Te6edf3rrc_dest_nameTff7b72=Ta5d6ff"Ta5d6ffrrc.hubTa5d6ff"Tb4b4b4,
Te6edf3rrc_auto_reconnectTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3rrc_persist_sessionsTff7b72=Tff7b72TrueTb4b4b4,
Tb4b4b4)

Tc9d1d9Key Methods
Tc9d1d9^^^^^^^^^^^

T79c0ff- Te6edf3:code:Te6edf3`get_landlock_status()`: Return Landlock LSM sandbox availability and activation state for the bot process
T79c0ff- Te6edf3:code:Te6edf3`run(delay=10)`: Start the bot's main loop
T79c0ff- Te6edf3:code:Te6edf3`send(destination, message, title="Reply", lxmf_fields=None, stamp_cost=None, opportunistic=None)`: Send a message to a destination, optionally with custom LXMF fields, stamp cost override, and opportunistic sending (tries direct, falls back to propagation immediately if configured).
T79c0ff- Te6edf3:code:Te6edf3`send_with_attachment(destination, message, attachment, title="Reply", stamp_cost=None, opportunistic=None)`: Send a message with an attachment
T79c0ff- Te6edf3:code:Te6edf3`command(name, description="No description provided", admin_only=False, threaded=False)`: Decorator for registering commands. Set Te6edf3:code:Te6edf3`threaded=True` to run the command's callback in a separate thread. Commands support type-hinted arguments for automatic conversion.
T79c0ff- Te6edf3:code:Te6edf3`intent(name, examples)`: Decorator for registering NLP intent handlers.
T79c0ff- Te6edf3:code:Te6edf3`nlp.export_model()`: Export trained NLP model data.
T79c0ff- Te6edf3:code:Te6edf3`nlp.import_model(model_data)`: Import previously exported NLP model data.
T79c0ff- Te6edf3:code:Te6edf3`request_link(destination_hash, callback=None, app_name="lxmf", *aspects)`: Request an RNS link to a destination. Allows custom Te6edf3:code:Te6edf3`app_name` and Te6edf3:code:Te6edf3`aspects` (defaults to "lxmf" and "delivery").
T79c0ff- Te6edf3:code:Te6edf3`on_link(callback)`: Register a handler for incoming RNS links.
T79c0ff- Te6edf3:code:Te6edf3`load_extension(name)`: Load a cog extension module by name (e.g., "cogs.utility").
T79c0ff- Te6edf3:code:Te6edf3`reload_extension(name)`: Reload a cog extension module.
T79c0ff- Te6edf3:code:Te6edf3`add_cog(cog_instance)`: Add a cog class instance to the bot.
T79c0ff- Te6edf3:code:Te6edf3`remove_cog(cog_name)`: Remove a cog from the bot by its class name.
T79c0ff- Te6edf3:code:Te6edf3`on_first_message()`: Decorator for handling first messages from users
T79c0ff- Te6edf3:code:Te6edf3`on_message()`: Decorator for handling all messages (called before command processing)
T79c0ff- Te6edf3:code:Te6edf3`validate()`: Run validation checks on the bot configuration
T79c0ff- Te6edf3:code:Te6edf3`connect_rrc(hub_hash, rooms=None, nick=None, dest_name=None, auto_reconnect=None)`: Connect to an RRC hub as a client
T79c0ff- Te6edf3:code:Te6edf3`disconnect_rrc(hub_hash=None)`: Disconnect one or all RRC hub sessions
T79c0ff- Te6edf3:code:Te6edf3`on_rrc(callback=None)`: Decorator or register handler for RRC events (Te6edf3:code:Te6edf3`handler(event, client, payload)`)
T79c0ff- Te6edf3:code:Te6edf3`rrc`: Te6edf3:code:Te6edf3`RRCManager` instance for multi-hub sessions

Tc9d1d9Structured Commands via LXMF Fields
Tc9d1d9-----------------------------------

Bots can receive commands sent via LXMF Ta5d6ff``Ta5d6ffFIELD_COMMANDSTa5d6ff`` (Ta5d6ff``Ta5d6ff0x09Ta5d6ff``) and automatically reply with Ta5d6ff``Ta5d6ffFIELD_RESULTSTa5d6ff`` (Ta5d6ff``Ta5d6ff0x0ATa5d6ff``). This enables structured request/response workflows alongside normal text commands.

Incoming Ta5d6ff``Ta5d6ffFIELD_COMMANDSTa5d6ff`` are parsed and routed through the same command registry as text commands, sharing permission checks, type-hinted argument parsing, threading, and middleware.

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3LXMFBotTb4b4b4, Te6edf3FIELD_COMMANDSTb4b4b4, Te6edf3FIELD_RESULTSTb4b4b4, Te6edf3pack_resultTb4b4b4, Te6edf3unpack_commands

Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffFieldBotTa5d6ff"Tb4b4b4)

Tf0883e@botTff7b72.Td2a8ffcommandTb4b4b4(Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffstatusTa5d6ff"Tb4b4b4, Te6edf3descriptionTff7b72=Ta5d6ff"Ta5d6ffReturn bot statusTa5d6ff"Tb4b4b4)
Tff7b72def Td2a8ffstatus_cmdTb4b4b4(Te6edf3ctxTb4b4b4)Tb4b4b4:
T8b949e# ctx.fields contains the raw LXMF fields dict
T8b949e# ctx.request_id is set automatically if the command included one
Te6edf3ctxTff7b72.Td2a8ffreplyTb4b4b4(Ta5d6ff"Ta5d6ffBot is onlineTa5d6ff"Tb4b4b4)

T8b949e# Sending a structured command from another LXMF client:
T8b949e# lxm.fields[FIELD_COMMANDS] = {"command": "status", "args": [], "request_id": "abc123"}
T8b949e# router.handle_outbound(lxm)

T8b949e# The bot reply automatically includes FIELD_RESULTS with the response and request_id.

To disable field command processing, set Ta5d6ff``Ta5d6fflxmf_commands_enabled=FalseTa5d6ff`` in Te6edf3:code:Te6edf3`BotConfig`.

Tc9d1d9Storage
Tc9d1d9-------

The framework provides three storage backends:

Tc9d1d9JSONStorage
Tc9d1d9^^^^^^^^^^^

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3JSONStorage

Te6edf3storage Tff7b72= Te6edf3JSONStorageTb4b4b4(Ta5d6ff"Ta5d6ffdataTa5d6ff"Tb4b4b4)

Tc9d1d9SQLiteStorage
Tc9d1d9^^^^^^^^^^^^^

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3SQLiteStorage

Te6edf3storage Tff7b72= Te6edf3SQLiteStorageTb4b4b4(Ta5d6ff"Ta5d6ffdata/bot.dbTa5d6ff"Tb4b4b4)

Tc9d1d9MemoryStorage
Tc9d1d9^^^^^^^^^^^^^

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfyT7ee787.T7ee787storage Tff7b72import Te6edf3MemoryStorage

Te6edf3storage Tff7b72= Te6edf3MemoryStorageTb4b4b4(Tb4b4b4) T8b949e# Entirely in-memory

Tc9d1d9Commands
Tc9d1d9--------

Command registration and handling:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tf0883e@botTff7b72.Td2a8ffcommandTb4b4b4(Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffhelloTa5d6ff"Tb4b4b4, Te6edf3descriptionTff7b72=Ta5d6ff"Ta5d6ffSays helloTa5d6ff"Tb4b4b4)
Tff7b72def Td2a8ffhelloTb4b4b4(Te6edf3ctxTb4b4b4)Tb4b4b4:
Te6edf3ctxTff7b72.Td2a8ffreplyTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffHello Tffd700{Te6edf3ctxTff7b72.Td2a8ffsenderTffd700}Ta5d6ff!Ta5d6ff"Tb4b4b4)

Tc9d1d9Type-Hinted Arguments
Tc9d1d9^^^^^^^^^^^^^^^^^^^^^

Commands automatically parse and convert arguments based on type hints in the callback function.

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tf0883e@botTff7b72.Td2a8ffcommandTb4b4b4(Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffaddTa5d6ff"Tb4b4b4, Te6edf3descriptionTff7b72=Ta5d6ff"Ta5d6ffAdds two numbersTa5d6ff"Tb4b4b4)
Tff7b72def Td2a8ffaddTb4b4b4(Te6edf3ctxTb4b4b4, Te6edf3aTb4b4b4: Tffa657intTb4b4b4, Te6edf3bTb4b4b4: Tffa657intTb4b4b4)Tb4b4b4:
Te6edf3result Tff7b72= Te6edf3a Tff7b72+ Te6edf3b
Te6edf3ctxTff7b72.Td2a8ffreplyTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffThe result is Tffd700{Te6edf3resultTffd700}Ta5d6ff"Tb4b4b4)

Tc9d1d9Help System
Tc9d1d9-----------

The framework includes an interactive help generator that provides beautiful, categorized help menus based on Cog and Command metadata.

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

T8b949e# The help command is automatically registered.
T8b949e# Users can use '/help' or '/help <command>'

Tc9d1d9Threaded Commands
Tc9d1d9^^^^^^^^^^^^^^^^^

For long-running or blocking operations that do not interact with the Reticulum Network Stack directly, you can run commands in a separate thread to keep the bot responsive.

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72import T7ee787time

Tf0883e@botTff7b72.Td2a8ffcommandTb4b4b4(Te6edf3nameTff7b72=Ta5d6ff"Ta5d6fflong_taskTa5d6ff"Tb4b4b4, Te6edf3descriptionTff7b72=Ta5d6ff"Ta5d6ffPerforms a long-running task in a separate threadTa5d6ff"Tb4b4b4, Te6edf3threadedTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72def Td2a8fflong_task_commandTb4b4b4(Te6edf3ctxTb4b4b4)Tb4b4b4:
Te6edf3ctxTff7b72.Td2a8ffreplyTb4b4b4(Ta5d6ff"Ta5d6ffStarting a long task... please wait.Ta5d6ff"Tb4b4b4)
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff10Tb4b4b4) T8b949e# This runs in a separate thread
Te6edf3ctxTff7b72.Td2a8ffreplyTb4b4b4(Ta5d6ff"Ta5d6ffLong task completed!Ta5d6ff"Tb4b4b4)

**Important:** Functions marked as Te6edf3:code:Te6edf3`threaded=True` **must not** directly interact with the Reticulum Network Stack (RNS) or any components that rely on Te6edf3:code:Te6edf3`lxmfy.transport.py`, as these are generally not thread-safe. Use Te6edf3:code:Te6edf3`ctx.reply()` for sending messages back to the user from within a threaded command.

Tc9d1d9Events
Tc9d1d9------

Event system for handling various bot events:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tf0883e@botTff7b72.Td2a8ffeventsTff7b72.Td2a8ffonTb4b4b4(Ta5d6ff"Ta5d6ffmessage_receivedTa5d6ff"Tb4b4b4, Te6edf3EventPriorityTff7b72.Td2a8ffHIGHESTTb4b4b4)
Tff7b72def Td2a8ffhandle_messageTb4b4b4(Te6edf3eventTb4b4b4)Tb4b4b4:
T8b949e# Handle message event
Tff7b72pass

Tc9d1d9Testing
Tc9d1d9-------

Project tests include reliability and stress scenarios in the repository test suite.
Use the repository's test runner to execute them.

Tc9d1d9Advanced Reliability Suite
Tc9d1d9^^^^^^^^^^^^^^^^^^^^^^^^^^

The framework includes an extensive suite of automated tests for harsh environments:

T79c0ff- **Manifold Testing**: Validates the mathematical topology of NLP intent vector space.
T79c0ff- **Chaos Engineering**: Simulates bit-rot, SD card failure, and storage corruption.
T79c0ff- **Temporal Drift**: Verifies resilience against system clock jumps (±1 year).
T79c0ff- **Leak Detection**: Long-term tracking of memory, file descriptors, and threads.

Tc9d1d9Permissions
Tc9d1d9-----------

Permission system for controlling access to bot features:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3DefaultPerms

Tf0883e@botTff7b72.Td2a8ffcommandTb4b4b4(Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffadminTa5d6ff"Tb4b4b4, Te6edf3descriptionTff7b72=Ta5d6ff"Ta5d6ffAdmin commandTa5d6ff"Tb4b4b4, Te6edf3admin_onlyTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72def Td2a8ffadmin_commandTb4b4b4(Te6edf3ctxTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3ctxTff7b72.Td2a8ffis_adminTb4b4b4:
Te6edf3ctxTff7b72.Td2a8ffreplyTb4b4b4(Ta5d6ff"Ta5d6ffAdmin command executedTa5d6ff"Tb4b4b4)

Tc9d1d9Middleware
Tc9d1d9----------

Middleware system for processing messages and events:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tf0883e@botTff7b72.Td2a8ffmiddlewareTff7b72.Td2a8ffregisterTb4b4b4(Te6edf3MiddlewareTypeTff7b72.Td2a8ffPRE_COMMANDTb4b4b4)
Tff7b72def Td2a8ffpre_command_middlewareTb4b4b4(Te6edf3ctxTb4b4b4)Tb4b4b4:
T8b949e# Process before command execution
Tff7b72pass

Tc9d1d9Attachments
Tc9d1d9-----------

Support for sending files, images, and audio:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3AttachmentTb4b4b4, Te6edf3AttachmentType

Te6edf3attachment Tff7b72= Te6edf3AttachmentTb4b4b4(
Tffa657typeTff7b72=Te6edf3AttachmentTypeTff7b72.Td2a8ffIMAGETb4b4b4,
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffimage.jpgTa5d6ff"Tb4b4b4,
Te6edf3dataTff7b72=Te6edf3image_dataTb4b4b4,
Tffa657formatTff7b72=Ta5d6ff"Ta5d6ffjpgTa5d6ff"
Tb4b4b4)
Te6edf3botTff7b72.Td2a8ffsend_with_attachmentTb4b4b4(Te6edf3destinationTb4b4b4, Ta5d6ff"Ta5d6ffHereTa5d6ff'Ta5d6ffs an imageTa5d6ff"Tb4b4b4, Te6edf3attachmentTb4b4b4)

Tc9d1d9Icon Appearance (LXMF Field)
Tc9d1d9-----------------------------

You can set a custom icon for your bot that compliant LXMF clients can display. This uses the Te6edf3:code:Te6edf3`LXMF.FIELD_ICON_APPEARANCE`.

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3IconAppearanceTb4b4b4, Te6edf3pack_icon_appearance_field
Tff7b72import T7ee787LXMF T8b949e# Required for LXMF.FIELD_ICON_APPEARANCE

T8b949e# Define the icon appearance
Te6edf3icon_data Tff7b72= Te6edf3IconAppearanceTb4b4b4(
Te6edf3icon_nameTff7b72=Ta5d6ff"Ta5d6ffsmart_toyTa5d6ff"Tb4b4b4, T8b949e# Name from Material Symbols
Te6edf3fg_colorTff7b72=Ta5d6ffbTa5d6ff'Tffea00\xFFTffea00\xFFTffea00\xFFTa5d6ff'Tb4b4b4, T8b949e# White foreground (3 bytes)
Te6edf3bg_colorTff7b72=Ta5d6ffbTa5d6ff'Tffea00\x4ATffea00\x90Tffea00\xE2Ta5d6ff' T8b949e# Blue background (3 bytes)
Tb4b4b4)

T8b949e# Pack it into the LXMF field format
Te6edf3icon_lxmf_field Tff7b72= Te6edf3pack_icon_appearance_fieldTb4b4b4(Te6edf3icon_dataTb4b4b4)

T8b949e# Send a message with this icon
Te6edf3botTff7b72.Td2a8ffsendTb4b4b4(
Te6edf3destination_hash_strTb4b4b4,
Ta5d6ff"Ta5d6ffHello from your friendly bot!Ta5d6ff"Tb4b4b4,
Te6edf3titleTff7b72=Ta5d6ff"Ta5d6ffBot MessageTa5d6ff"Tb4b4b4,
Te6edf3lxmf_fieldsTff7b72=Te6edf3icon_lxmf_field
Tb4b4b4)

T8b949e# You can also combine it with other fields, like attachments:
T8b949e# attachment_field = pack_attachment(some_attachment)
T8b949e# combined_fields = {**icon_lxmf_field, **attachment_field}
T8b949e# bot.send(destination, "Message with icon and attachment", lxmf_fields=combined_fields)

Tc9d1d9Scheduler
Tc9d1d9---------

Task scheduling system:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tf0883e@botTff7b72.Td2a8ffschedulerTff7b72.Td2a8ffscheduleTb4b4b4(Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffdaily_taskTa5d6ff"Tb4b4b4, Te6edf3cron_exprTff7b72=Ta5d6ff"Ta5d6ff0 0 * * *Ta5d6ff"Tb4b4b4)
Tff7b72def Td2a8ffdaily_taskTb4b4b4(Tb4b4b4)Tb4b4b4:
T8b949e# Run daily at midnight
Tff7b72pass

Tc9d1d9Signatures
Tc9d1d9----------

LXMFy provides configuration options for LXMF's built-in cryptographic message signing and verification:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3LXMFBot

Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffSecureBotTa5d6ff"Tb4b4b4,
Te6edf3signature_verification_enabledTff7b72=Tff7b72TrueTb4b4b4, T8b949e# Enable signature checks
Te6edf3require_message_signaturesTff7b72=Tff7b72False T8b949e# Set to True to reject unsigned messages
Tb4b4b4)

**Important:** LXMF automatically handles all cryptographic signing and verification using RNS identities. LXMFy's Te6edf3:code:Te6edf3`SignatureManager` is a configuration layer that:

T79c0ff- Controls whether to enforce signature verification
T79c0ff- Determines policy for unsigned messages (accept or reject)
T79c0ff- Integrates with the permission system (e.g., bypass verification for trusted users)

The actual cryptographic operations are performed by LXMF/RNS, not by LXMFy.

Tc9d1d9Landlock LSM Sandbox
Tc9d1d9^^^^^^^^^^^^^^^^^^^^

On Linux kernels with Landlock support (5.13+), LXMFy can restrict filesystem access for the bot process and for external script cogs.

**Bot process sandbox**

When Te6edf3:code:Te6edf3`landlock_enabled=True` (default) and not running in Te6edf3:code:Te6edf3`test_mode`, the bot calls Te6edf3:code:Te6edf3`apply_landlock_sandbox()` during initialization. System directories are read-only; bot storage, config, cogs, Reticulum config, and temp paths remain writable.

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffSecureBotTa5d6ff"Tb4b4b4,
Te6edf3landlock_enabledTff7b72=Tff7b72TrueTb4b4b4,
Tb4b4b4)

Te6edf3status Tff7b72= Te6edf3botTff7b72.Td2a8ffget_landlock_statusTb4b4b4(Tb4b4b4)
T8b949e# status keys: landlock_kernel_supported, landlock_requested,
T8b949e# landlock_auto_enabled, landlock_disabled_by_env, landlock_active

**Environment override**

T79c0ff- Te6edf3:code:Te6edf3`LXMFY_LANDLOCK=0`: disable Landlock even on supported kernels
T79c0ff- Te6edf3:code:Te6edf3`LXMFY_LANDLOCK=1`: attempt Landlock on Linux regardless of auto-detection
T79c0ff- unset: follow Te6edf3:code:Te6edf3`landlock_enabled` and kernel auto-detection

**External cog sandbox**

Script cogs use Te6edf3:code:Te6edf3`external_cogs_sandbox_type`. In Te6edf3:code:Te6edf3`auto` mode, Landlock is preferred when available because it requires no external tools. See the Ta5d6ff`Creating Bots Tffd700<creating-bots.html>Ta5d6ff`_ guide for the full sandbox option list.

Tc9d1d9Identity Pinning
Tc9d1d9^^^^^^^^^^^^^^^^

LXMFy supports optional identity pinning to prevent impersonation if an identity is rotated or compromised. When enabled, the bot "pins" an LXMF address to its first-seen public key.

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3identity_pinning_enabledTff7b72=Tff7b72True
Tb4b4b4)

Tc9d1d9SignatureManager Methods
Tc9d1d9^^^^^^^^^^^^^^^^^^^^^^^^

The Te6edf3:code:Te6edf3`SignatureManager` is available as Te6edf3:code:Te6edf3`bot.signature_manager` when Te6edf3:code:Te6edf3`signature_verification_enabled=True`:

T79c0ff- Te6edf3:code:Te6edf3`should_verify_message(sender)`: Determine if a message from the given sender should be verified
T79c0ff- Te6edf3:code:Te6edf3`handle_unsigned_message(sender, message_hash)`: Handle messages that lack valid signatures based on policy

Tc9d1d9How LXMF Signatures Work
Tc9d1d9^^^^^^^^^^^^^^^^^^^^^^^^^

LXMF automatically signs all outgoing messages using the sender's RNS identity during the Te6edf3:code:Te6edf3`pack()` operation. When messages are received, LXMF validates signatures and provides:

T79c0ff- Te6edf3:code:Te6edf3`message.signature_validated`: Boolean indicating if the signature is valid
T79c0ff- Te6edf3:code:Te6edf3`message.unverified_reason`: Reason code if validation failed (e.g., Te6edf3:code:Te6edf3`SIGNATURE_INVALID`, Te6edf3:code:Te6edf3`SOURCE_UNKNOWN`)

LXMFy uses these built-in LXMF properties to enforce your bot's signature policy.

Tc9d1d9Message Delivery
Tc9d1d9----------------

LXMFy provides advanced message delivery features including propagation nodes and automatic retries:

Tc9d1d9Propagation Nodes
Tc9d1d9^^^^^^^^^^^^^^^^^

Send messages through specific propagation nodes for improved reliability on the Reticulum network:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

T8b949e# Configure the propagation node once at config/runtime level
Te6edf3botTff7b72.Td2a8ffset_propagation_nodeTb4b4b4(Ta5d6ff"Ta5d6ff<propagation_node_hash>Ta5d6ff"Tb4b4b4)

T8b949e# Send using configured delivery behavior
Te6edf3botTff7b72.Td2a8ffsendTb4b4b4(
Te6edf3destination_hashTb4b4b4,
Ta5d6ff"Ta5d6ffMessage contentTa5d6ff"
Tb4b4b4)

T8b949e# The propagation node hash should be a valid LXMF propagation node
T8b949e# on the Reticulum network

Tc9d1d9Automatic Retries
Tc9d1d9^^^^^^^^^^^^^^^^^

Configure automatic retry attempts for failed direct deliveries:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffReliableBotTa5d6ff"Tb4b4b4,
Te6edf3direct_delivery_retriesTff7b72=T79c0ff5Tb4b4b4, T8b949e# Retry direct delivery up to 5 times
Te6edf3propagation_fallback_enabledTff7b72=Tff7b72True
Tb4b4b4)

Te6edf3botTff7b72.Td2a8ffsendTb4b4b4(Te6edf3destination_hashTb4b4b4, Ta5d6ff"Ta5d6ffImportant messageTa5d6ff"Tb4b4b4)

T8b949e# Default direct_delivery_retries is 3
T8b949e# Retry logic automatically handles delivery callbacks

The retry system tracks delivery attempts per destination and automatically retries failed deliveries. Successful deliveries reset the retry counter for that destination.

Tc9d1d9Message Persistence
Tc9d1d9^^^^^^^^^^^^^^^^^^^

Outgoing messages can be persisted to disk to ensure they are delivered even after a bot restart. Persistence is enabled by default. The in-memory outbound queue is bounded (Te6edf3:code:Te6edf3`message_queue_size`, default 50) and drops the oldest message when full. Invalid destination hashes are not restored.

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3message_persistence_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3message_queue_sizeTff7b72=T79c0ff50Tb4b4b4,
Tb4b4b4)

Tc9d1d9Message Handlers
Tc9d1d9----------------

LXMFy provides decorators for handling different types of incoming messages:

Tc9d1d9First Message Handler
Tc9d1d9^^^^^^^^^^^^^^^^^^^^^

Handle the first message from each user:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tf0883e@botTff7b72.Td2a8ffon_first_messageTb4b4b4(Tb4b4b4)
Tff7b72def Td2a8ffwelcome_userTb4b4b4(Te6edf3senderTb4b4b4, Te6edf3messageTb4b4b4)Tb4b4b4:
Te6edf3content Tff7b72= Te6edf3messageTff7b72.Td2a8ffcontentTff7b72.Td2a8ffdecodeTb4b4b4(Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)
Te6edf3botTff7b72.Td2a8ffsendTb4b4b4(Te6edf3senderTb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffWelcome! You said: Tffd700{Te6edf3contentTffd700}Ta5d6ff"Tb4b4b4)
Tff7b72return Tff7b72True T8b949e# Return True to stop further processing

Tc9d1d9General Message Handler
Tc9d1d9^^^^^^^^^^^^^^^^^^^^^^^

Handle all incoming messages before command processing:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tf0883e@botTff7b72.Td2a8ffon_messageTb4b4b4(Tb4b4b4)
Tff7b72def Td2a8ffhandle_all_messagesTb4b4b4(Te6edf3senderTb4b4b4, Te6edf3messageTb4b4b4)Tb4b4b4:
Te6edf3content Tff7b72= Te6edf3messageTff7b72.Td2a8ffcontentTff7b72.Td2a8ffdecodeTb4b4b4(Ta5d6ff"Ta5d6ffutf-8Ta5d6ff"Tb4b4b4)Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)
T8b949e# Custom logic here
Tff7b72if Te6edf3contentTff7b72.Td2a8ffstartswithTb4b4b4(Ta5d6ff"Ta5d6ffecho:Ta5d6ff"Tb4b4b4)Tb4b4b4:
Te6edf3botTff7b72.Td2a8ffsendTb4b4b4(Te6edf3senderTb4b4b4, Te6edf3contentTb4b4b4[T79c0ff5Tb4b4b4:Tb4b4b4]Tb4b4b4)
Tff7b72return Tff7b72True T8b949e# Stop further processing
Tff7b72return Tff7b72False T8b949e# Continue to command processing

Message handlers are called in this order:
T79c0ff1. First message handler (if this is the first message from this sender)
T79c0ff2. General message handlers (registered with Te6edf3:code:Te6edf3`on_message()`)
T79c0ff3. Command processing (if message starts with command prefix)

Tc9d1d9Reticulum Relay Chat (RRC)
Tc9d1d9--------------------------

Bots can join Ta5d6ff`RRC Tffd700<https://rrc.kc1awv.net/>Ta5d6ff`_ hubs over RNS Links with CBOR envelopes. Package: Te6edf3:code:Te6edf3`lxmfy.rrc`.

Tc9d1d9BotConfig options
Tc9d1d9^^^^^^^^^^^^^^^^^

T79c0ff* Te6edf3:code:Te6edf3`rrc_enabled` (bool, default Te6edf3:code:Te6edf3`False`): Connect configured hubs on startup
T79c0ff* Te6edf3:code:Te6edf3`rrc_hubs` (list of hex hashes): Hub destination hashes
T79c0ff* Te6edf3:code:Te6edf3`rrc_rooms` (list of str): Rooms to auto-join after WELCOME
T79c0ff* Te6edf3:code:Te6edf3`rrc_nick` (str or None): Nickname on HELLO and room messages
T79c0ff* Te6edf3:code:Te6edf3`rrc_dest_name` (str, default Te6edf3:code:Te6edf3`"rrc.hub"`): Destination name used to build the hub destination
T79c0ff* Te6edf3:code:Te6edf3`rrc_auto_reconnect` (bool, default Te6edf3:code:Te6edf3`True`): Reconnect after link loss
T79c0ff* Te6edf3:code:Te6edf3`rrc_persist_sessions` (bool, default Te6edf3:code:Te6edf3`True`): Persist hubs and rooms across restarts
T79c0ff* Te6edf3:code:Te6edf3`reticulum_config_dir` (str or None): Reticulum config directory. Also set via Te6edf3:code:Te6edf3`LXMFY_RETICULUM_CONFIG_DIR`. Use the same config as MeshChatX (often Te6edf3:code:Te6edf3`~/.reticulum`) so hub announces are visible.

Tc9d1d9Example
Tc9d1d9^^^^^^^

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfy Tff7b72import Te6edf3LXMFBotTb4b4b4, Te6edf3RRCMessage

Te6edf3bot Tff7b72= Te6edf3LXMFBotTb4b4b4(
Te6edf3nameTff7b72=Ta5d6ff"Ta5d6ffRoomBotTa5d6ff"Tb4b4b4,
Te6edf3reticulum_config_dirTff7b72=Ta5d6ff"Ta5d6ff~/.reticulumTa5d6ff"Tb4b4b4,
Te6edf3rrc_enabledTff7b72=Tff7b72TrueTb4b4b4,
Te6edf3rrc_hubsTff7b72=Tb4b4b4[Ta5d6ff"Ta5d6ff664fc0e8d2e448658e37bb3f34e6c88fTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3rrc_roomsTff7b72=Tb4b4b4[Ta5d6ff"Ta5d6ffgeneralTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3rrc_nickTff7b72=Ta5d6ff"Ta5d6ffRoomBotTa5d6ff"Tb4b4b4,
Tb4b4b4)

Tf0883e@botTff7b72.Td2a8ffon_rrc
Tff7b72def Td2a8ffon_rrcTb4b4b4(Te6edf3eventTb4b4b4, Te6edf3clientTb4b4b4, Te6edf3payloadTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3event Tff7b72== Ta5d6ff"Ta5d6ffmsgTa5d6ff" Tff7b72and Tffa657isinstanceTb4b4b4(Te6edf3payloadTb4b4b4, Te6edf3RRCMessageTb4b4b4) Tff7b72and Te6edf3payloadTff7b72.Td2a8ffmentionTb4b4b4:
Te6edf3clientTff7b72.Td2a8ffsend_messageTb4b4b4(Te6edf3payloadTff7b72.Td2a8ffroomTb4b4b4, Ta5d6fffTa5d6ff"Ta5d6ffHi Tffd700{Te6edf3payloadTff7b72.Td2a8ffnickTffd700}Ta5d6ff"Tb4b4b4)

T8b949e# Runtime API
T8b949e# bot.connect_rrc(hub_hash, rooms=["general"])
T8b949e# bot.rrc.send_message("general", "hello")
T8b949e# bot.rrc.send_notice("general", "notice")
T8b949e# bot.rrc.send_action("general", "waves")
T8b949e# bot.rrc.join("ops")
T8b949e# bot.rrc.part("ops")
T8b949e# bot.rrc.status()
T8b949e# bot.disconnect_rrc()

Tc9d1d9Exported types
Tc9d1d9^^^^^^^^^^^^^^

T79c0ff* Te6edf3:code:Te6edf3`RRCClient`: Single-hub session
T79c0ff* Te6edf3:code:Te6edf3`RRCManager`: Multi-hub manager (Te6edf3:code:Te6edf3`bot.rrc`)
T79c0ff* Te6edf3:code:Te6edf3`RRCMessage`: Room event payload (Te6edf3:code:Te6edf3`kind`, Te6edf3:code:Te6edf3`room`, Te6edf3:code:Te6edf3`text`, Te6edf3:code:Te6edf3`nick`, Te6edf3:code:Te6edf3`src`, Te6edf3:code:Te6edf3`mention`, ...)
T79c0ff* Te6edf3:code:Te6edf3`RRC_VERSION`: Wire protocol version constant

Common events passed to Te6edf3:code:Te6edf3`@bot.on_rrc` handlers include Te6edf3:code:Te6edf3`status`, Te6edf3:code:Te6edf3`welcome`, Te6edf3:code:Te6edf3`joined`, Te6edf3:code:Te6edf3`parted`, Te6edf3:code:Te6edf3`msg`, Te6edf3:code:Te6edf3`notice`, Te6edf3:code:Te6edf3`action`, Te6edf3:code:Te6edf3`motd`, Te6edf3:code:Te6edf3`error`, and Te6edf3:code:Te6edf3`rtt`.

Tc9d1d9Templates
Tc9d1d9=========

The framework includes several ready-to-use bot templates:

Tc9d1d9EchoBot
Tc9d1d9-------

Simple echo bot that repeats messages:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfyT7ee787.T7ee787templates Tff7b72import Te6edf3EchoBot

Te6edf3bot Tff7b72= Te6edf3EchoBotTb4b4b4(Tb4b4b4)
Te6edf3botTff7b72.Td2a8ffrunTb4b4b4(Tb4b4b4)

Tc9d1d9NoteBot
Tc9d1d9-------

Note-taking bot with JSON storage:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfyT7ee787.T7ee787templates Tff7b72import Te6edf3NoteBot

Te6edf3bot Tff7b72= Te6edf3NoteBotTb4b4b4(Tb4b4b4)
Te6edf3botTff7b72.Td2a8ffrunTb4b4b4(Tb4b4b4)

Tc9d1d9ReminderBot
Tc9d1d9-----------

Reminder bot with SQLite storage:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfyT7ee787.T7ee787templates Tff7b72import Te6edf3ReminderBot

Te6edf3bot Tff7b72= Te6edf3ReminderBotTb4b4b4(Tb4b4b4)
Te6edf3botTff7b72.Td2a8ffrunTb4b4b4(Tb4b4b4)

Tc9d1d9RRCBot
Tc9d1d9------

RRC room bot that joins configured hubs and replies to Te6edf3:code:Te6edf3`@mentions`. Defaults to hub Te6edf3:code:Te6edf3`664fc0e8d2e448658e37bb3f34e6c88f`, room Te6edf3:code:Te6edf3`#general`, and Te6edf3:code:Te6edf3`~/.reticulum` when available.

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72from T7ee787lxmfyT7ee787.T7ee787templates Tff7b72import Te6edf3RRCBot

Te6edf3bot Tff7b72= Te6edf3RRCBotTb4b4b4(
Te6edf3hubsTff7b72=Tb4b4b4[Ta5d6ff"Ta5d6ff664fc0e8d2e448658e37bb3f34e6c88fTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3roomsTff7b72=Tb4b4b4[Ta5d6ff"Ta5d6ffgeneralTa5d6ff"Tb4b4b4]Tb4b4b4,
Te6edf3nickTff7b72=Ta5d6ff"Ta5d6ffRRCBotTa5d6ff"Tb4b4b4,
Te6edf3reticulum_config_dirTff7b72=Ta5d6ff"Ta5d6ff~/.reticulumTa5d6ff"Tb4b4b4,
Tb4b4b4)
Te6edf3botTff7b72.Td2a8ffrunTb4b4b4(Tb4b4b4)

Tc9d1d9CLI Tools
Tc9d1d9=========

The framework provides command-line tools for bot management:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72bash

T8b949e# Create a new bot
lxmfy create mybot

T8b949e# Create a bot from template
lxmfy create --template Tffa657echo mybot
lxmfy create --template rrc my_rrc_bot

T8b949e# Run a template bot
lxmfy run Tffa657echo
lxmfy run rrc

T8b949e# Test signature verification with a message
lxmfy signatures Tffa657test

T8b949e# Enable signature verification
lxmfy signatures Tffa657enable

T8b949e# Disable signature verification
lxmfy signatures disable

Tc9d1d9Error Handling
Tc9d1d9==============

The framework provides comprehensive error handling:

Tb4b4b4.. Tff7b72code-blockTb4b4b4:: Tff7b72python

Tff7b72tryTb4b4b4:
Te6edf3botTff7b72.Td2a8ffrunTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149KeyboardInterruptTb4b4b4:
Te6edf3botTff7b72.Td2a8ffcleanupTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149Exception Tff7b72as Te6edf3eTb4b4b4:
Te6edf3loggerTff7b72.Td2a8fferrorTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffError running bot: Tffd700{Tffa657strTb4b4b4(Te6edf3eTb4b4b4)Tffd700}Ta5d6ff"Tb4b4b4)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────